home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / xWindows definition files / xTextFileWindow.p < prev    next >
Encoding:
Text File  |  1993-12-11  |  12.2 KB  |  422 lines  |  [TEXT/PJMM]

  1. unit xFileTextWindow;
  2.  
  3. { This unit defines a subclass, xFileTextWindow, of xWindow that implements the }
  4. { file operations necessary for saving and reading short (up to 16000 characters) }
  5. { text files.  It also defines a number of procedures for dealing with commands from }
  6. { the File Menu. }
  7.  
  8. { NOTE: To use this unit (or at least, to use the procedure UpdateFileMenu), you must }
  9. { change the resource file from generic.rsrc to TextPrint.rsrs in the Run Options }
  10. { dialog box. }
  11.  
  12.  
  13. interface
  14.  
  15. uses
  16.     xWindow, xTextWindow;
  17.  
  18. type
  19.     xFileTextWindow = object(xTextWindow)
  20.  
  21.             fromFile: boolean;   { Was the text in this window read from a file? }
  22.             fileName: string;      { If so, these two variables hold the data necessary }
  23.             fileVRef: integer;       { to re-open that file when the window contents are saved. }
  24.  
  25.             nextTextWin: xFileTextWindow;  { This unit keeps a list of text windows that }
  26.               { have been opened.  This is a reference to the next window in that list. }
  27.  
  28.             procedure openInRect (title: string;
  29.                                         left, top, right, bottom: integer);
  30.             override;
  31.            { Open the window and initialize its instance variables. }
  32.             procedure doSave (var done: boolean);
  33.            { Save the contents of the window in a file; done will be false if an error }
  34.            { occurs or if the user cancels the operation, and will be false otherwise. }
  35.            { If the window was originally read from a file, the data is saved to the }
  36.            { same file without further user action; otherwise, doSaveAs is called. }
  37.             procedure doSaveAs (var done: boolean);
  38.            { Similar to doSave, except that the user is asked to specify a file to be }
  39.            { created. }
  40.             procedure doClose;
  41.             override;
  42.            { Close the window and dispose of its data strutures; if the data in the }
  43.            { window has been altered since it was loaded or saved, the user is given }
  44.            { a chance to save it before closing, and can choose to abort the close }
  45.            { operation at that time. }
  46.         end;
  47.  
  48. procedure InitTextFileWindows;
  49.     { MUST be called when the program starts up, if anything else from this unit is }
  50.     { to be used. }
  51.  
  52. procedure doSaveCommand;
  53.     { Respond to the Save command from the file menu. }
  54.  
  55. procedure doSaveAsCommand;
  56.     { Respond to the Save As command from teh file menu. }
  57.  
  58. procedure doNewCommand;
  59.     { Respond to the New command from the file Menu. }
  60.  
  61. procedure doOpenCommand;
  62.     { Respond to the Open command from the File Menu. }
  63.  
  64. procedure doCloseCommand;
  65.     { Respond to the Close command from the File Menu. }
  66.  
  67. procedure UpdateFileMenu (fileMenu: menuHandle);
  68.     { Update the file menu as appropriate depending on whether the front window is }
  69.     { an xTextFileWindow, and whether it has been modified or not.  IMPORTANT NOTE: }
  70.     { It is assumed that the first five entries in the File Menu are New, Open, Save, }
  71.     { Save As, and  Close, in that order. }
  72.  
  73. procedure CloseAllBeforeQuitting (var done: boolean);
  74.     { This procedure should be called in response to the quit command.  It will give }
  75.     { the user a chance to save any unsaved data before quitting.  The user can also }
  76.     { choose to cancel.  If the user cancels or if an error occurs while saving a file, }
  77.     { Done will be set to false; otherwise it will be true (and the program should end. }
  78.  
  79.  
  80. implementation
  81.  
  82. var
  83.     newCt: integer;  { number of untitiled windows that have been opened. }
  84.     firstWin: xFileTextWindow;  { linked list of open windows. }
  85.  
  86. type
  87.     response = (answerYes, answerNo, answerCancel);
  88.  
  89. procedure InitTextFileWindows;
  90.     begin
  91.         newCt := 0;
  92.         firstWin := nil;
  93.     end;
  94.  
  95. { NOTE: the next two procedures require the presense of certain ALRT and DITL }
  96. { resources in the resource file for this project. }
  97.  
  98. function YesNoCancel (message: string): Response;
  99.     var
  100.         bttn: integer;
  101.     begin
  102.         ParamText(message, '', '', '');
  103.         bttn := CautionAlert(131, nil);
  104.         case bttn of
  105.             1: 
  106.                 YesNoCancel := answerYes;
  107.             2: 
  108.                 YesNoCancel := answerNo;
  109.             3: 
  110.                 YesNoCancel := answerCancel;
  111.         end;
  112.     end;
  113.  
  114. function YesNo (message: string): Response;
  115.     var
  116.         bttn: integer;
  117.     begin
  118.         ParamText(message, '', '', '');
  119.         bttn := CautionAlert(130, nil);
  120.         case bttn of
  121.             1: 
  122.                 YesNo := answerYes;
  123.             2: 
  124.                 YesNo := answerNo;
  125.         end;
  126.     end;
  127.  
  128. procedure xFileTextWindow.openInRect (title: string;
  129.                                 left, top, right, bottom: integer);
  130.     begin
  131.         inherited openInRect(title, left, top, right, bottom);
  132.         fromFile := false;
  133.         nextTextWin := firstWin;
  134.         firstWin := self;
  135.         maxChars := 15000;
  136.     end;
  137.  
  138. procedure xFileTextWindow.doSave (var done: boolean);
  139.     var
  140.         err: OSErr;
  141.         refNum: integer;
  142.         chars: CharsHandle;
  143.         count: longint;
  144.     begin
  145.         if (not fromFile) | trimmed then
  146.             doSaveAs(done)
  147.         else begin
  148.                 done := false;
  149.                 err := FSOpen(fileName, fileVRef, refNum);
  150.                 if err <> noErr then begin
  151.                         TellUser(StringOf('Some error has occured while trying to open file ', fileName, '.  (Macintosh err number ', err : 1, '.)'));
  152.                         EXIT(doSave);
  153.                     end;
  154.                 chars := GetText;
  155.                 count := GetHandleSize(Handle(chars));
  156.                 HLock(handle(chars));
  157.                 err := FSWrite(refNum, count, Ptr(chars^));
  158.                 HUnLock(handle(chars));
  159.                 if err <> noErr then begin
  160.                         TellUser(StringOf('Some error has occured while trying to write to file ', fileName, '.  (Macintosh err number ', err : 1, '.)'));
  161.                         err := FSClose(refNum);
  162.                         EXIT(doSave);
  163.                     end;
  164.                 err := FSClose(refNum);
  165.                 done := true;
  166.                 declareClean;
  167.             end;
  168.     end;
  169.  
  170. procedure xFileTextWindow.doSaveAs (var done: boolean);
  171.     var
  172.         count: longint;
  173.         refNum: integer;
  174.         theSFReply: SFReply;
  175.         err: OSErr;
  176.         pt: point;
  177.         name: str255;
  178.         chars: CharsHandle;
  179.     begin
  180.         done := false;
  181.         if trimmed then
  182.             TellUser('Note that, because of the large amount of text in this window, data from the beginning has been lost.');
  183.         pt.h := 50;
  184.         pt.v := 80;
  185.         name := GetTitle;
  186.         SFPutFile(pt, 'Save as: ', name, nil, theSFReply);
  187.         if not theSFReply.good then
  188.             EXIT(doSaveAs);
  189.         err := Create(theSFReply.fName, theSFReply.vRefNum, 'ttxt', 'TEXT');
  190.         if err = dupFNErr then begin
  191.                 err := FSDelete(theSFReply.fName, theSFReply.vRefNum);
  192.                 if err <> noErr then begin
  193.                         TellUser(StringOf('Some error has occured while trying to delete old file.  (Macintosh err number ', err : 1, '.)'));
  194.                         EXIT(doSaveAs);
  195.                     end;
  196.                 err := Create(theSFReply.fName, theSFReply.vRefNum, 'ttxt', 'TEXT');
  197.             end;
  198.         if err <> noErr then begin
  199.                 TellUser(StringOf('Some error has occured while trying to create file ', fileName, '.  (Macintosh err number ', err : 1, '.)'));
  200.                 EXIT(doSaveAs);
  201.             end;
  202.         err := FSOpen(theSFReply.fName, theSFReply.vRefNum, refNum);
  203.         if err <> noErr then begin
  204.                 TellUser(StringOf('Some error has occured while trying to open file ', fileName, '.  (Macintosh err number ', err : 1, '.)'));
  205.                 EXIT(doSaveAs);
  206.             end;
  207.         chars := GetText;
  208.         count := GetHandleSize(Handle(chars));
  209.         HLock(handle(chars));
  210.         err := FSWrite(refNum, count, Ptr(chars^));
  211.         HUnLock(handle(chars));
  212.         if err <> noErr then begin
  213.                 TellUser(StringOf('Some error has occured while trying to write to file ', fileName, '.  (Macintosh err number ', err : 1, '.)'));
  214.                 err := FSClose(refNum);
  215.                 EXIT(doSaveAs);
  216.             end;
  217.         err := FSClose(refNum);
  218.         done := true;
  219.         fileName := theSFReply.fName;
  220.         fileVRef := theSFReply.vRefNum;
  221.         fromFile := true;
  222.         declareClean;
  223.     end;
  224.  
  225. procedure xFileTextWindow.doclose;
  226.     var
  227.         runner: xFileTextWindow;
  228.         ans: response;
  229.         done: boolean;
  230.     begin
  231.         if dirty then begin
  232.                 ans := YesNoCancel(StringOf('Do you want to save ', GetTitle, ' before closing its window?'));
  233.                 if ans = answerCancel then
  234.                     EXIT(doClose);
  235.                 if ans = answerYes then begin
  236.                         doSave(done);
  237.                         if not done then
  238.                             EXIT(doClose);
  239.                     end;
  240.             end;
  241.         if firstWin = self then
  242.             firstWin := firstWin.nextTextWin
  243.         else begin
  244.                 runner := firstWin;
  245.                 while (runner <> nil) & (runner.nextTextWin <> self) do
  246.                     runner := runner.nextTextWin;
  247.                 if runner <> nil then
  248.                     runner.nextTextWin := runner.nextTextWin.nextTextWin;
  249.             end;
  250.         inherited doclose;
  251.     end;
  252.  
  253. procedure doNewCommand;
  254.     var
  255.         win: xFileTextWindow;
  256.     begin
  257.         new(win);
  258.         newCt := newCt + 1;
  259.         win.open(StringOf('Untitled ', newCt : 1));
  260.     end;
  261.  
  262. procedure doOpenCommand;
  263.     var
  264.         err: OSErr;
  265.         count: longint;
  266.         fileRef: integer;
  267.         theSFReply: SFReply;
  268.         win: xFileTextWindow;
  269.         chars: CharsHandle;
  270.         tooBig: boolean;
  271.         theTypeList: SFTypeList;
  272.         pt: point;
  273.         ans: response;
  274.     begin
  275.         pt.h := 50;
  276.         pt.v := 80;
  277.         theTypeList[0] := 'TEXT';
  278.         SFGetFile(pt, 'File to open:', nil, 1, theTypeList, nil, theSFReply);
  279.         if not theSFReply.good then
  280.             Exit(DoOpenCommand);
  281.         err := FSOpen(theSFReply.fName, theSFReply.vRefNum, fileRef);
  282.         if err <> noErr then begin
  283.                 TellUser(StringOf('Some error has occured while trying to open file.   (Macintosh error ', err : 1, ')'));
  284.                 Exit(DoOpenCommand);
  285.             end;
  286.         err := GetEOF(fileRef, count);
  287.         if err <> noErr then begin
  288.                 TellUser(StringOf('Some error has occured while trying to access file.   (Macintosh error ', err : 1, ')'));
  289.                 Exit(DoOpenCommand);
  290.             end;
  291.         tooBig := false;
  292.         if count > 16000 then begin
  293.                 count := 16000;
  294.                 tooBig := true;
  295.             end;
  296.         chars := CharsHandle(NewHandle(count));
  297.         if memError <> noErr then begin
  298.                 TellUser('There is not enough memory to load that file; try closing some other windows.');
  299.                 Exit(DoOpenCommand);
  300.             end;
  301.         if toobig then begin
  302.                 ans := YesNo('The file is too big for this program.  Do you want to read the first 16000 characters?');
  303.                 if ans = answerNo then begin
  304.                         DisposHandle(Handle(chars));
  305.                         err := FSClose(fileRef);
  306.                         EXIT(doOpenCommand);
  307.                     end;
  308.             end;
  309.         HLock(Handle(chars));
  310.         err := FSRead(fileRef, count, Ptr(chars^));
  311.         HUnlock(Handle(chars));
  312.         if err <> noErr then begin
  313.                 err := FSClose(fileRef);
  314.                 DisposHandle(Handle(chars));
  315.                 TellUser(StringOf('An error has occured while trying to read the file.  (Macintosh error ', err : 1, ')'));
  316.                 Exit(DoOpenCommand);
  317.             end;
  318.         err := FSClose(fileRef);
  319.         new(win);
  320.         if toobig then begin
  321.                 newCt := newCt + 1;
  322.                 win.open(StringOf('Untitled ', newCt : 1));
  323.             end
  324.         else
  325.             win.open(theSFReply.fName);
  326.         win.InstallText(chars);
  327.         if not tooBig then begin
  328.                 win.fromFile := true;
  329.                 win.fileName := theSFReply.fName;
  330.                 win.fileVRef := theSFReply.vRefNum;
  331.             end;
  332.     end;
  333.  
  334. procedure doSaveCommand;
  335.     var
  336.         win: WindowPtr;
  337.         xWin: xWindow;
  338.         dummy: boolean;
  339.     begin
  340.         win := frontWindow;
  341.         if (win <> nil) & (WindowPeek(win)^.refCon <> 0) then begin
  342.                 xwin := xWindow(WindowPeek(win)^.refCon);
  343.                 if member(xWin, xFileTextWindow) then
  344.                     xFileTextWindow(xWin).doSave(dummy);
  345.             end;
  346.     end;
  347.  
  348. procedure doSaveAsCommand;
  349.     var
  350.         win: WindowPtr;
  351.         xWin: xWindow;
  352.         dummy: boolean;
  353.     begin
  354.         win := frontWindow;
  355.         if (win <> nil) & (WindowPeek(win)^.refCon <> 0) then begin
  356.                 xwin := xWindow(WindowPeek(win)^.refCon);
  357.                 if member(xWin, xFileTextWindow) then
  358.                     xFileTextWindow(xWin).doSaveAs(dummy);
  359.             end;
  360.     end;
  361.  
  362. procedure doCloseCommand;
  363.     var
  364.         win: WindowPtr;
  365.         xWin: xWindow;
  366.     begin
  367.         win := FrontWindow;
  368.         if (win <> nil) & (WindowPeek(win)^.refCon <> 0) then begin
  369.                 xWin := xWindow(windowPeek(win)^.refCon);
  370.                 xWin.doClose;
  371.             end;
  372.     end;
  373.  
  374. procedure UpdateFileMenu (fileMenu: menuHandle);
  375.     var
  376.         win: WindowPtr;
  377.         xWin: xWindow;
  378.         i: integer;
  379.     begin
  380.         win := FrontWindow;
  381.         for i := 3 to 5 do
  382.             DisableItem(fileMenu, i);
  383.         if (win <> nil) & (WindowPeek(win)^.refCon <> 0) then begin
  384.                 xWin := xWindow(WindowPeek(win)^.refCon);
  385.                 if member(xWin, xFileTextWindow) then
  386.                     with xFileTextWindow(xWin) do begin
  387.                             EnableItem(filemenu, 5);
  388.                             EnableItem(filemenu, 4);
  389.                             if changed then
  390.                                 EnableItem(fileMenu, 3);
  391.                         end;
  392.             end;
  393.     end;
  394.  
  395. procedure CloseAllBeforeQuitting (var done: boolean);
  396.     var
  397.         runner, runner2: xFileTextWindow;
  398.         ans: response;
  399.     begin
  400.         done := true;
  401.         runner := FirstWin;
  402.         while runner <> nil do begin
  403.                 with runner do
  404.                     if dirty then begin
  405.                             ans := YesNoCancel(StringOf('Do you want to save ', GetTitle, ' before quitting?'));
  406.                             if ans = answerCancel then begin
  407.                                     done := false;
  408.                                     EXIT(CloseAllBeforeQuitting);
  409.                                 end;
  410.                             if ans = answerYes then begin
  411.                                     doSave(done);
  412.                                     if not done then
  413.                                         EXIT(CloseAllBeforeQuitting);
  414.                                 end;
  415.                             declareClean; { to avoid asking user about closing in procedure doClose }
  416.                             doClose
  417.                         end;
  418.                 runner := runner.nextTextWin;
  419.             end;
  420.     end;
  421.  
  422. end.